package org.ccay.core.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;

import org.ccay.core.exception.impl.CommonSystemException;

/**
 * Xml 工具类
 * 
 * 
 * @since 2012-9-13
 */
public final class XmlUtil {
	/**
	 * 防止实例
	 */
	private XmlUtil(){
	}
	 
	/**
	 * 系列化被@XMLRootElement注解的对象	
	 * 
	 * @since 2013-7-11
	 * @param obj
	 * @return
	 */
	public static <T> String marshal(Object obj) {
		JAXBContext jaxbContext;
		StringWriter sw = new StringWriter();
		try {
			jaxbContext = JAXBContext.newInstance(obj.getClass());
			Marshaller marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_ENCODING, EncodingUtil.UTF_8);

			
			marshaller.marshal(obj, sw);
			return sw.getBuffer().toString();
		} catch (JAXBException e) {
			throw new CommonSystemException("Unable to execute marshal.", e);
		} finally {
			StreamUtil.closeStreams(sw);
		}
	}
	/**
	 * 	系列化指定命名空间和prefix的元素
	 * 
	 * @since 2013-7-11
	 * @param object
	 * @param cls
	 * @param rootElementName
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static   String marshal(Object object, Class  cls, String rootElementName,String namespace,String prefix) {
		JAXBContext jaxbContext;
		StringWriter sw = new StringWriter();
		try {
			jaxbContext = JAXBContext.newInstance(object.getClass());
			Marshaller marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_ENCODING, EncodingUtil.UTF_8);

			JAXBElement  jaxbElement = new JAXBElement(new QName(namespace,rootElementName,prefix), cls, object);
			marshaller.marshal(jaxbElement, sw);
			return sw.getBuffer().toString();
		} catch (JAXBException e) {
			throw new CommonSystemException("Unable to execute marshal.", e);
		} finally {
			StreamUtil.closeStreams(sw);
		}
	}
	/** 
	 * 序列化为字符串
	 * @param object 目标对象
	 * @param cls 目标对象的类型
	 * @param rootElementName 根节点元素名
	 * @return 序列化后的字符串 
	 */
	public static   String marshal(Object object, Class  cls, String rootElementName) {
		JAXBContext jaxbContext;
		StringWriter sw = new StringWriter();
		try {
			jaxbContext = JAXBContext.newInstance(object.getClass());
			Marshaller marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_ENCODING, EncodingUtil.UTF_8);

			JAXBElement  jaxbElement = new JAXBElement(new QName(rootElementName), cls, object);
			marshaller.marshal(jaxbElement, sw);
			return sw.getBuffer().toString();
		} catch (JAXBException e) {
			throw new CommonSystemException("Unable to execute marshal.", e);
		} finally {
			StreamUtil.closeStreams(sw);
		}
	}
	
	/** 
	 * 反序列化	
	 * @param input 输入字符串
	 * @param cls 反序列化成的类型
	 * @return 反序列化后的对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T unmarshal(String input, Class<T> cls) {
		StringReader sr = new StringReader(input);
		try {
			JAXBContext context = JAXBContext.newInstance(cls);			
			Unmarshaller unmarshaller = context.createUnmarshaller();
			
			return (T) unmarshaller.unmarshal(sr);
		} catch (PropertyException e) {
			throw new CommonSystemException("Unable to execute unmarshal.", e);
		} catch (JAXBException e) {
			throw new CommonSystemException("Unable to execute unmarshal.", e);
		} finally {
			StreamUtil.closeStreams(sr);
		}
	}
	/**
	 * 对输入流进行反序列化	
	 * 
	 * @since 2013-7-11
	 * @param input
	 * @param cls
	 * @return
	 */
	public static <T> T unmarshal(InputStream input, Class<T> cls) {
		 
		try {
			JAXBContext context = JAXBContext.newInstance(cls);			
			Unmarshaller unmarshaller = context.createUnmarshaller();
			
			return (T) unmarshaller.unmarshal(input);
		} catch (PropertyException e) {
			throw new CommonSystemException("Unable to execute unmarshal.", e);
		} catch (JAXBException e) {
			throw new CommonSystemException("Unable to execute unmarshal.", e);
		}  
	}
	
	
	/** 
	 * 判断文件是否可以实体注入
	 * 
	 * @since 2016年11月7日
	 * @param is
	 * @return
	 * @throws IOException
	 */
	public static boolean isXXE(InputStream is) throws IOException {
		String str = StreamUtil.getSteamString(is);
		if (str.indexOf("<!ENTITY") != -1 || str.indexOf("<!DOCTYPE") != -1) {
			return true;
		}
		return false;
	}
	
	/** 
	 * 判断文件是否可以实体注入
	 * 
	 * @since 2016年11月7日
	 * @param zipIs
	 * @return
	 * @throws IOException
	 */
	public static boolean isXXE(ZipInputStream zipIs) throws IOException {
		ZipEntry entry = null;
		while ((entry = zipIs.getNextEntry()) != null) {
			if (!entry.isDirectory()) {
				if (isXXE((InputStream)zipIs)) {
					return true;
				}
			}
		}
		return false;
	}
}
